package com.fjut.zr.judge_system.OJ.OJS;

import com.fjut.zr.judge_system.OJ.OjSubmitter;
import com.fjut.zr.judge_system.POJO.PO.TOjResultPO;
import com.fjut.zr.judge_system.POJO.VO.SubmitResult;
import com.fjut.zr.judge_system.Util.ApplicationContextHelper;
import com.fjut.zr.judge_system.Util.MyClient;
import com.fjut.zr.judge_system.Util.strLen;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public abstract class BaseOJ implements Runnable{

    Environment env= ApplicationContextHelper.getBean(Environment.class);
    public String rid;
    public String pid;
    public int time;
    public int memory;
    public String code;
    public String run=env.getProperty("OJ.config.judge.run");
    public String data=env.getProperty("OJ.config.judge.data");
    public SubmitResult submitResult=new SubmitResult();
    public int maxtime=0;
    public int maxmemory=0;
    public String language;
    String url=env.getProperty("OJ.config.return.pathIp");
    /**
     * 提交
     * @param rid
     * @param pid
     * @param time
     * @param memory
     * @param code
     */
    public void submit(String rid, String pid, int time, int memory, String code) {
        this.rid=rid;
        this.pid=pid;
        this.time=time;
        this.memory=memory;
        this.code=code;
        submitResult.setCodelength(strLen.getLength(code));
        submitResult.setPid(pid);
        submitResult.setRid(rid);
    }
    /**
     * 创建文件夹
     * @param file
     */
    public abstract void mkTemporaryDirs(File file);

    /**
     *写入文件
     * @param context
     * @param file
     * @return
     */
    public Boolean inputStreamToFile(String context, File file) {
        OutputStream os = null;
        Boolean flag = false;
        // 如果写入的文件不存在
        if (!file.exists()) {
            try {
                // 创建一个
                file.createNewFile();
                System.out.println("第二次创建文件成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        file.setExecutable(true);
        file.setReadable(true);
        file.setWritable(true);
        try {
            // 创建文件字节输出流
            os = new FileOutputStream(file);
            // 写入代码
            os.write(context.getBytes("GBK"));
            if (os != null) {
                os.close();
            }
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            if (os != null) {
                try {
                    // 关闭文件字节输出流
                    os.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            return flag;
        }
        return flag;
    }

    /**
     * 执行linux命令
     * @param cmd
     * @return
     */
    public String doOrder(String cmd) throws IOException {
        StringBuilder result = new StringBuilder();
        Process process = null;
        BufferedReader bufrIn = null;
        BufferedReader bufrError = null;
        try {
            // 执行命令, 返回一个子进程对象（命令在子进程中执行）
            process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",cmd});

            // 方法阻塞, 等待命令执行完成（成功会返回0）
            process.waitFor();

            // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出（PS: 子进程的输出就是主进程的输入）
            bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
            // 读取输出
            String line = null;
            while ((line = bufrIn.readLine()) != null) {
                result.append(line).append('\n');
            }
            while ((line = bufrError.readLine()) != null) {
                result.append(line).append('\n');
            }

        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        } finally {
            bufrIn.close();
            bufrError.close();
            // 销毁子进程
            if (process != null) {
                process.destroy();
            }
        }
        return String.valueOf(result);
    }

    /**
     * 获取输入文件列表
     * @param filepath
     * @return
     */
    public List<String> getInList(String filepath) throws IOException {
        List<String> inlist=new ArrayList<>();
        Process process = null;
        BufferedReader bufrIn = null;
        BufferedReader bufrError = null;
        try {
            // 执行命令, 返回一个子进程对象（命令在子进程中执行）
            process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","ls "+filepath});

            // 方法阻塞, 等待命令执行完成（成功会返回0）
            process.waitFor();

            // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出（PS: 子进程的输出就是主进程的输入）
            bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));

            // 读取输出
            String line = null;
            while ((line = bufrIn.readLine()) != null) {
                if(line.substring(line.length() - 3).equals(".in")) {
                    inlist.add(line);
                }
            }
            while ((line = bufrError.readLine()) != null) {
                inlist.add(line);
            }

        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        } finally {
            bufrIn.close();
            bufrError.close();
            // 销毁子进程
            if (process != null) {
                process.destroy();
            }
        }
        return inlist;
    }

    /**
     * 获取输入文件列表
     * @param filepath
     * @return
     */
    public List<String> getOutList(String filepath) throws IOException {
        List<String> outlist=new ArrayList<>();
        Process process = null;
        BufferedReader bufrIn = null;
        BufferedReader bufrError = null;
        try {
            // 执行命令, 返回一个子进程对象（命令在子进程中执行）
            process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","ls "+filepath});

            // 方法阻塞, 等待命令执行完成（成功会返回0）
            process.waitFor();

            // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出（PS: 子进程的输出就是主进程的输入）
            bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));

            // 读取输出
            String line = null;
            while ((line = bufrIn.readLine()) != null) {
                if(line.substring(line.length() - 4).equals(".out")) {
                    outlist.add(line);
                }
            }
            while ((line = bufrError.readLine()) != null) {
                outlist.add(line);
            }

        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        } finally {
            bufrIn.close();
            bufrError.close();
            // 销毁子进程
            if (process != null) {
                process.destroy();
            }
        }
        return outlist;
    }

    /**
     * 编译
     * @param code
     * @param pid
     * @param rid
     */
    public abstract void complie(String code,String pid,String rid) throws IOException;

    /**
     * 运行所有用例
     * @param rid
     * @param pid
     * @param inlist
     * @param time
     * @param memory
     * @return
     */
    public String run(String rid, String pid, List<String> inlist, int time, int memory) {
        for(String infile:inlist)
        {
            String complieresult=runcode(rid,pid,infile,time,memory);
            if(complieresult.equals("Complie Success")==false)
            {
                return complieresult;
            }
        }
        return "Complie Success";
    }

    /**
     * 运行代码
     * @param rid
     * @param pid
     * @param infile
     * @param time
     * @param memory
     * @return
     */
    public abstract String runcode(String rid,String pid,String infile,int time,int memory);

    /**
     * 消费缓冲区代码
     * @param is
     * @return
     */
    public String consumeInputStream(InputStream is)
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String s ;
        StringBuilder sb = new StringBuilder();
        try {
            while((s=br.readLine())!=null){
                sb.append(s);
                System.out.println(sb);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 评测
     * @param rid
     * @param pid
     * @param outlist
     * @return
     */
    public double judge(String rid,String pid,List<String> outlist) throws IOException
    {
        int allnum = 0, fnum = 0;
        for (String outfile : outlist) {
            allnum++;
            String simple = doOrder("cat " + data + pid + "/" + outfile);
            String result = doOrder("cat " + run + rid + "/result/" + outfile);
            if (simple.hashCode() != result.hashCode()) {
                fnum++;
//                System.out.println("输出不匹配");
                continue;
            } else {
                if(simple.equals(result)==false)
                {
                    fnum++;
//                    System.out.println("输出不匹配");
                    continue;
                }
            }
        }
        submitResult.setAllcount(allnum);
        submitResult.setAccount(allnum-fnum);
        return (double) ((double) (allnum-fnum)/allnum*1.0)*100;
    }
    public void returnResult()
    {
        MyClient client = new MyClient();
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        formparams.add(new BasicNameValuePair("rid",this.submitResult.getRid()));
        formparams.add(new BasicNameValuePair("problem",submitResult.getPid()));
        formparams.add(new BasicNameValuePair("result",submitResult.getResult()));
        formparams.add(new BasicNameValuePair("resultInfo",submitResult.getErrorinfo()));
        formparams.add(new BasicNameValuePair("memory",submitResult.getMemory()+"KB"));
        formparams.add(new BasicNameValuePair("time",submitResult.getTime()+"MS"));
        formparams.add(new BasicNameValuePair("language",language));
        formparams.add(new BasicNameValuePair("codeLength",String.valueOf(submitResult.getCodelength())));
        System.out.println(client.Post(url+"fjut/judge_status/getJudgeResult", formparams));

    }

}
